#include <stdio.h>
#include "iot_ali.h"

#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"

#include "lwip/err.h"
#include "lwip/sys.h"

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include "aiot_state_api.h"
#include "aiot_sysdep_api.h"
#include "aiot_mqtt_api.h"

#include "ds18b20.h"
#include "dht11.h"
#include "fan.h"
#include "mq2.h"
#include "cJSON.h"

float dtemp_low = 10, dtemp_high = 30, dAlarmSwitch = 0, dFanSwitch = 0, dh_low = 10, dh_high = 60;

void *mqtt_handle = NULL;
/* FreeRTOS event group to signal when we are connected*/
static EventGroupHandle_t s_wifi_event_group;

/* The event group allows multiple bits for each event, but we only care about two events:
 * - we are connected to the AP with an IP
 * - we failed to connect after the maximum amount of retries */
#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT BIT1

/* TODO: 替换为自己设备的三元组 */
char *product_key = "k0gooxF1iG8";
char *device_name = "device1";
char *device_secret = "a6b2d46d9d1e959f01fa39844e7ffdac";

char *pub_topic = "/sys/k0gooxF1iG8/device1/thing/event/property/post";
    
char send_buf[200];
int res2;
/* 位于portfiles/aiot_port文件夹下的系统适配函数集合 */
extern aiot_sysdep_portfile_t g_aiot_sysdep_portfile;

/* 位于external/ali_ca_cert.c中的服务器证书 */
extern const char *ali_ca_cert;

static pthread_t g_mqtt_process_thread;
static pthread_t g_mqtt_recv_thread;
static uint8_t g_mqtt_process_thread_running = 0;
static uint8_t g_mqtt_recv_thread_running = 0;

/* TODO: 如果要关闭日志, 就把这个函数实现为空, 如果要减少日志, 可根据code选择不打印
 *
 * 例如: [1577589489.033][LK-0317] mqtt_basic_demo&a13FN5TplKq
 *
 * 上面这条日志的code就是0317(十六进制), code值的定义见core/aiot_state_api.h
 *
 */

/* 日志回调函数, SDK的日志会从这里输出 */
int32_t demo_state_logcb(int32_t code, char *message)
{
    // printf("%s", message);

    return 0;
}

/* MQTT事件回调函数, 当网络连接/重连/断开时被触发, 事件定义见core/aiot_mqtt_api.h */
void demo_mqtt_event_handler(void *handle, const aiot_mqtt_event_t *event, void *userdata)
{
    switch (event->type)
    {
    /* SDK因为用户调用了aiot_mqtt_connect()接口, 与mqtt服务器建立连接已成功 */
    case AIOT_MQTTEVT_CONNECT:
    {
        printf("AIOT_MQTTEVT_CONNECT\n");
        /* TODO: 处理SDK建连成功, 不可以在这里调用耗时较长的阻塞函数 */
    }
    break;

    /* SDK因为网络状况被动断连后, 自动发起重连已成功 */
    case AIOT_MQTTEVT_RECONNECT:
    {
        printf("AIOT_MQTTEVT_RECONNECT\n");
        /* TODO: 处理SDK重连成功, 不可以在这里调用耗时较长的阻塞函数 */
    }
    break;

    /* SDK因为网络的状况而被动断开了连接, network是底层读写失败, heartbeat是没有按预期得到服务端心跳应答 */
    case AIOT_MQTTEVT_DISCONNECT:
    {
        char *cause = (event->data.disconnect == AIOT_MQTTDISCONNEVT_NETWORK_DISCONNECT) ? ("network disconnect") : ("heartbeat disconnect");
        printf("AIOT_MQTTEVT_DISCONNECT: %s\n", cause);
        /* TODO: 处理SDK被动断连, 不可以在这里调用耗时较长的阻塞函数 */
    }
    break;

    default:
    {
    }
    }
}

/* MQTT默认消息处理回调, 当SDK从服务器收到MQTT消息时, 且无对应用户回调处理时被调用 */
void demo_mqtt_default_recv_handler(void *handle, const aiot_mqtt_recv_t *packet, void *userdata)
{
    switch (packet->type)
    {
    case AIOT_MQTTRECV_HEARTBEAT_RESPONSE:
    {
        printf("heartbeat response\n");
        /* TODO: 处理服务器对心跳的回应, 一般不处理 */
    }
    break;

    case AIOT_MQTTRECV_SUB_ACK:
    {
        printf("suback, res: -0x%04X, packet id: %d, max qos: %d\n",
               -packet->data.sub_ack.res, packet->data.sub_ack.packet_id, packet->data.sub_ack.max_qos);
        /* TODO: 处理服务器对订阅请求的回应, 一般不处理 */
    }
    break;

    case AIOT_MQTTRECV_PUB:
    {
        // printf("pub, qos: %d, topic: %.*s\n", packet->data.pub.qos, packet->data.pub.topic_len, packet->data.pub.topic);
        // printf("\r\n");
        printf("pub, payload: %.*s\n", packet->data.pub.payload_len, packet->data.pub.payload);
        printf("\r\n");
        /* TODO: 处理服务器下发的业务报文 */

        cJSON *a = cJSON_Parse((char *)(packet->data.pub.payload));
        // printf("body:\r\n%s  \r\n", packet->data.pub.payload);
        // if (a != NULL)
        // {
        //     printf("yes this is cjson txt\r\n");
        // }
        // else
        // {
        //     printf("no!\r\n");
        // }
        
        cJSON *params_rec = cJSON_GetObjectItem(a, "params");
        
        // temp_low  temp_high    AlarmSwitch   FanSwitch      h_low   h_high
        cJSON *temp_low = cJSON_GetObjectItem(params_rec, "temp_low");
        cJSON *temp_high = cJSON_GetObjectItem(params_rec, "temp_high");
        cJSON *AlarmSwitch = cJSON_GetObjectItem(params_rec, "AlarmSwitch");
        cJSON *FanSwitch = cJSON_GetObjectItem(params_rec, "FanSwitch");
        cJSON *h_low = cJSON_GetObjectItem(params_rec, "h_low");
        cJSON *h_high = cJSON_GetObjectItem(params_rec, "h_high");

    int res;


        if (temp_low != NULL)
        {
            dtemp_low = temp_low->valuedouble;
            sprintf(send_buf, "{\"id\":\"1701849534490\",\"version\":\"1.0\",\"params\":{\"temp_low\":%.0f}}", dtemp_low);
            res2 = 1;
        }
        if (res2 == 1)
        {
            res2 = 0;
            res = aiot_mqtt_pub(mqtt_handle, pub_topic, (uint8_t *)send_buf, strlen(send_buf), 0);
            if (res < 0)
            {
                printf("aiot_mqtt_sub failed, res: -0x%04X\n", -res);
                return -1;
            }
        }

        if (temp_high != NULL)
        {
            dtemp_high = temp_high->valuedouble;
            sprintf(send_buf, "{\"id\":\"1701849534490\",\"version\":\"1.0\",\"params\":{\"temp_high\":%.0f}}", dtemp_high);
            res2 = 1;
        }
        if (res2 == 1)
        {
            res2 = 0;
            res = aiot_mqtt_pub(mqtt_handle, pub_topic, (uint8_t *)send_buf, strlen(send_buf), 0);
            if (res < 0)
            {
                printf("aiot_mqtt_sub failed, res: -0x%04X\n", -res);
                return -1;
            }
        }
        if (AlarmSwitch != NULL)
        {
            dAlarmSwitch = AlarmSwitch->valueint;
            sprintf(send_buf, "{\"id\":\"1701849534490\",\"version\":\"1.0\",\"params\":{\"AlarmSwitch\":%.0f}}", dAlarmSwitch);
            res2 = 1;
        }
        if (res2 == 1)
        {
            res2 = 0;
            res = aiot_mqtt_pub(mqtt_handle, pub_topic, (uint8_t *)send_buf, strlen(send_buf), 0);
            if (res < 0)
            {
                printf("aiot_mqtt_sub failed, res: -0x%04X\n", -res);
                return -1;
            }
        }
        if (FanSwitch != NULL)
        {
            dFanSwitch = FanSwitch->valueint;
            sprintf(send_buf, "{\"id\":\"1701849534490\",\"version\":\"1.0\",\"params\":{\"FanSwitch\":%.0f}}", dFanSwitch);
            res2 = 1;
        }
        if (res2 == 1)
        {
            res2 = 0;
            res = aiot_mqtt_pub(mqtt_handle, pub_topic, (uint8_t *)send_buf, strlen(send_buf), 0);
            if (res < 0)
            {
                printf("aiot_mqtt_sub failed, res: -0x%04X\n", -res);
                return -1;
            }
        }
        if (h_low != NULL)
        {
            dh_low = h_low->valueint;
            sprintf(send_buf, "{\"id\":\"1701849534490\",\"version\":\"1.0\",\"params\":{\"h_low\":%.0f}}", dh_low);
            res2 = 1;
        }
        if (h_high != NULL)
        {
            dh_high = h_high->valueint;
            sprintf(send_buf, "{\"id\":\"1701849534490\",\"version\":\"1.0\",\"params\":{\"h_high\":%.0f}}", dh_high);
            res2 = 1;
        }
        if (res2 == 1)
        {
            res2 = 0;
            res = aiot_mqtt_pub(mqtt_handle, pub_topic, (uint8_t *)send_buf, strlen(send_buf), 0);
            if (res < 0)
            {
                printf("aiot_mqtt_sub failed, res: -0x%04X\n", -res);
                return -1;
            }
        }

    }
    break;

    case AIOT_MQTTRECV_PUB_ACK:
    {
        printf("puback, packet id: %d\n", packet->data.pub_ack.packet_id);
        /* TODO: 处理服务器对QoS1上报消息的回应, 一般不处理 */
    }
    break;

    default:
    {
    }
    }
}

/* 执行aiot_mqtt_process的线程, 包含心跳发送和QoS1消息重发 */
void *demo_mqtt_process_thread(void *args)
{
    int32_t res = STATE_SUCCESS;

    while (g_mqtt_process_thread_running)
    {
        res = aiot_mqtt_process(args);
        if (res == STATE_USER_INPUT_EXEC_DISABLED)
        {
            break;
        }
        sleep(1);
    }
    return NULL;
}

/* 执行aiot_mqtt_recv的线程, 包含网络自动重连和从服务器收取MQTT消息 */
void *demo_mqtt_recv_thread(void *args)
{
    int32_t res = STATE_SUCCESS;

    while (g_mqtt_recv_thread_running)
    {
        res = aiot_mqtt_recv(args);
        if (res < STATE_SUCCESS)
        {
            if (res == STATE_USER_INPUT_EXEC_DISABLED)
            {
                break;
            }
            sleep(1);
        }
    }
    return NULL;
}

int linkkit_main(void)
{
    int32_t res = STATE_SUCCESS;
    char *url = "iot-as-mqtt.cn-shanghai.aliyuncs.com"; /* 阿里云平台上海站点的域名后缀 */
    char host[100] = {0};                               /* 用这个数组拼接设备连接的云平台站点全地址, 规则是 ${productKey}.iot-as-mqtt.cn-shanghai.aliyuncs.com */
    uint16_t port = 443;                                /* 无论设备是否使用TLS连接阿里云平台, 目的端口都是443 */
    aiot_sysdep_network_cred_t cred;                    /* 安全凭据结构体, 如果要用TLS, 这个结构体中配置CA证书等参数 */

    /* 配置SDK的底层依赖 */
    aiot_sysdep_set_portfile(&g_aiot_sysdep_portfile);
    /* 配置SDK的日志输出 */
    aiot_state_set_logcb(demo_state_logcb);

    /* 创建SDK的安全凭据, 用于建立TLS连接 */
    memset(&cred, 0, sizeof(aiot_sysdep_network_cred_t));
    cred.option = AIOT_SYSDEP_NETWORK_CRED_SVRCERT_CA; /* 使用RSA证书校验MQTT服务端 */
    cred.max_tls_fragment = 16384;                     /* 最大的分片长度为16K, 其它可选值还有4K, 2K, 1K, 0.5K */
    cred.sni_enabled = 1;                              /* TLS建连时, 支持Server Name Indicator */
    cred.x509_server_cert = ali_ca_cert;               /* 用来验证MQTT服务端的RSA根证书 */
    cred.x509_server_cert_len = strlen(ali_ca_cert);   /* 用来验证MQTT服务端的RSA根证书长度 */

    /* 创建1个MQTT客户端实例并内部初始化默认参数 */
    mqtt_handle = aiot_mqtt_init();
    if (mqtt_handle == NULL)
    {
        printf("aiot_mqtt_init failed\n");
        return -1;
    }

    /* TODO: 如果以下代码不被注释, 则例程会用TCP而不是TLS连接云平台 */
    /*
    {
        memset(&cred, 0, sizeof(aiot_sysdep_network_cred_t));
        cred.option = AIOT_SYSDEP_NETWORK_CRED_NONE;
    }
    */

    snprintf(host, 100, "%s.%s", product_key, url);
    /* 配置MQTT服务器地址 */
    aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_HOST, (void *)host);
    /* 配置MQTT服务器端口 */
    aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_PORT, (void *)&port);
    /* 配置设备productKey */
    aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_PRODUCT_KEY, (void *)product_key);
    /* 配置设备deviceName */
    aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_DEVICE_NAME, (void *)device_name);
    /* 配置设备deviceSecret */
    aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_DEVICE_SECRET, (void *)device_secret);
    /* 配置网络连接的安全凭据, 上面已经创建好了 */
    aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_NETWORK_CRED, (void *)&cred);
    /* 配置MQTT默认消息接收回调函数 */
    aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_RECV_HANDLER, (void *)demo_mqtt_default_recv_handler);
    /* 配置MQTT事件回调函数 */
    aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_EVENT_HANDLER, (void *)demo_mqtt_event_handler);

    /* 与服务器建立MQTT连接 */
    res = aiot_mqtt_connect(mqtt_handle);
    if (res < STATE_SUCCESS)
    {
        /* 尝试建立连接失败, 销毁MQTT实例, 回收资源 */
        aiot_mqtt_deinit(&mqtt_handle);
        printf("aiot_mqtt_connect failed: -0x%04X\n", -res);
        return -1;
    }

    /* MQTT 订阅topic功能示例, 请根据自己的业务需求进行使用 */
    {
        // received topic=/sys/k0gooxF1iG8/device1/thing/service/property/set, payload={"method":"thing.service.property.set","id":"786598144","params":{"FanSwitch":1},"version":"1.0.0"}
        // char *sub_topic = "/sys/k0gooxF1iG8/device1/thing/event/FanSwitch/post_reply";
        // // char *sub_topic = "/sys/k0gooxF1iG8/device1/thing/event/property/post";

        // res = aiot_mqtt_sub(mqtt_handle, sub_topic, NULL, 1, NULL);
        // if (res < 0)
        // {
        //     printf("aiot_mqtt_sub failed, res: -0x%04X\n", -res);
        //     return -1;
        // }
        // char *sub_topic2 = "/sys/k0gooxF1iG8/device1/thing/service/property/set";
        // res = aiot_mqtt_sub(mqtt_handle, sub_topic, NULL, 1, NULL);
        // if (res < 0)
        // {
        //     printf("aiot_mqtt_sub failed, res: -0x%04X\n", -res);
        //     return -1;
        // }
    }

    /* MQTT 发布消息功能示例, 请根据自己的业务需求进行使用 */
    // {

    //     // /sys/k0gooxF1iG8/device1/thing/service/property/set
    //     // publish topic=/sys/k0gooxF1iG8/device1/thing/event/property/post, payload={"id":1701849534490,"params":{"Humidity":12},"version":"1.0","method":"thing.event.property.post"}
    

    char *pub_payload = "{\"id\":\"1701849534490\",\"version\":\"1.0\",\"params\":{\"Humidity\":40}}";

    res = aiot_mqtt_pub(mqtt_handle, pub_topic, (uint8_t *)pub_payload, strlen(pub_payload), 0);
    if (res < 0)
    {
        printf("aiot_mqtt_sub failed, res: -0x%04X\n", -res);
        return -1;
    }
    //     char *pub_payload2 = "{\"id\":\"1701849534490\",\"version\":\"1.0\",\"params\":{\"temperature\":32}}";

    //     res = aiot_mqtt_pub(mqtt_handle, pub_topic, (uint8_t *)pub_payload2, strlen(pub_payload2), 0);
    //     if (res < 0)
    //     {
    //         printf("aiot_mqtt_sub failed, res: -0x%04X\n", -res);
    //         return -1;
    //     }
    // }

    /* 创建一个单独的线程, 专用于执行aiot_mqtt_process, 它会自动发送心跳保活, 以及重发QoS1的未应答报文 */
    g_mqtt_process_thread_running = 1;
    res = pthread_create(&g_mqtt_process_thread, NULL, demo_mqtt_process_thread, mqtt_handle);
    if (res < 0)
    {
        printf("pthread_create demo_mqtt_process_thread failed: %d\n", res);
        return -1;
    }

    /* 创建一个单独的线程用于执行aiot_mqtt_recv, 它会循环收取服务器下发的MQTT消息, 并在断线时自动重连 */
    g_mqtt_recv_thread_running = 1;
    res = pthread_create(&g_mqtt_recv_thread, NULL, demo_mqtt_recv_thread, mqtt_handle);
    if (res < 0)
    {
        printf("pthread_create demo_mqtt_recv_thread failed: %d\n", res);
        return -1;
    }
    int cnt = 0;
    char pub_str[200];
    
            sprintf(pub_str, "{\"id\":\"1701849534490\",\"version\":\"1.0\",\"params\":{\"AlarmSwitch\":%d}}", 1);
            res = aiot_mqtt_pub(mqtt_handle, pub_topic, (uint8_t *)pub_str, strlen(pub_str), 0);
            if (res < 0)
            {
                printf("aiot_mqtt_sub failed, res: -0x%04X\n", -res);
                return -1;
            }
    // char *pub_topic = "/sys/k0gooxF1iG8/device1/thing/event/property/post";
    /* 主循环进入休眠 */
    while (1)
    {

        // if(fan_state == 1)
        // {
        //     sprintf(pub_str, "{\"id\":\"1701849534490\",\"version\":\"1.0\",\"params\":{\"FanSwitch\":%d}}", 1);
        //     res = aiot_mqtt_pub(mqtt_handle, pub_topic, (uint8_t *)pub_str, strlen(pub_str), 0);
        //     if (res < 0)
        //     {
        //         printf("aiot_mqtt_sub failed, res: -0x%04X\n", -res);
        //         return -1;
        //     }
        // }
        // else
        // {
        //     sprintf(pub_str, "{\"id\":\"1701849534490\",\"version\":\"1.0\",\"params\":{\"FanSwitch\":%d}}", 0);
        //     res = aiot_mqtt_pub(mqtt_handle, pub_topic, (uint8_t *)pub_str, strlen(pub_str), 0);
        //     if (res < 0)
        //     {
        //         printf("aiot_mqtt_sub failed, res: -0x%04X\n", -res);
        //         return -1;
        //     }
        // }
        // if(mq2_state == 1)
        // {
        //     sprintf(pub_str, "{\"id\":\"1701849534490\",\"version\":\"1.0\",\"params\":{\"AlarmSwitch\":%d}}", 1);
        //     res = aiot_mqtt_pub(mqtt_handle, pub_topic, (uint8_t *)pub_str, strlen(pub_str), 0);
        //     if (res < 0)
        //     {
        //         printf("aiot_mqtt_sub failed, res: -0x%04X\n", -res);
        //         return -1;
        //     }
        // }
        // else
        // {
        //     sprintf(pub_str, "{\"id\":\"1701849534490\",\"version\":\"1.0\",\"params\":{\"AlarmSwitch\":%d}}", 0);
        //     res = aiot_mqtt_pub(mqtt_handle, pub_topic, (uint8_t *)pub_str, strlen(pub_str), 0);
        //     if (res < 0)
        //     {
        //         printf("aiot_mqtt_sub failed, res: -0x%04X\n", -res);
        //         return -1;
        //     }
        // }

        if (T != 0)
        {
            sprintf(pub_str, "{\"id\":\"1701849534490\",\"version\":\"1.0\",\"params\":{\"Humidity\":%d}}", H);
            res = aiot_mqtt_pub(mqtt_handle, pub_topic, (uint8_t *)pub_str, strlen(pub_str), 0);
            if (res < 0)
            {
                printf("aiot_mqtt_sub failed, res: -0x%04X\n", -res);
                return -1;
            }
        }
        if (H != 0)
        {
            sprintf(pub_str, "{\"id\":\"1701849534490\",\"version\":\"1.0\",\"params\":{\"temperature\":%.1f}}", T);
            res = aiot_mqtt_pub(mqtt_handle, pub_topic, (uint8_t *)pub_str, strlen(pub_str), 0);
            if (res < 0)
            {
                printf("aiot_mqtt_sub failed, res: -0x%04X\n", -res);
                return -1;
            }
        }
        sleep(5);
    }

    /* 断开MQTT连接, 一般不会运行到这里 */
    res = aiot_mqtt_disconnect(mqtt_handle);
    if (res < STATE_SUCCESS)
    {
        aiot_mqtt_deinit(&mqtt_handle);
        printf("aiot_mqtt_disconnect failed: -0x%04X\n", -res);
        return -1;
    }

    /* 销毁MQTT实例, 一般不会运行到这里 */
    res = aiot_mqtt_deinit(&mqtt_handle);
    if (res < STATE_SUCCESS)
    {
        printf("aiot_mqtt_deinit failed: -0x%04X\n", -res);
        return -1;
    }

    g_mqtt_process_thread_running = 0;
    g_mqtt_recv_thread_running = 0;
    pthread_join(g_mqtt_process_thread, NULL);
    pthread_join(g_mqtt_recv_thread, NULL);

    return 0;
}
